package aga.sokoban.model;

import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;

public class LevelCollectionSerializer {

	public LevelCollection load(InputStream in) throws Exception {
		DocumentBuilder builder = DocumentBuilderFactory.newInstance()
				.newDocumentBuilder();
		Document doc = builder.parse(in);
		LevelCollection res = new LevelCollection();
		NodeList roots = doc.getElementsByTagName("SokobanLevels");
		for (int i = 0; i < roots.getLength(); i++) {
			readRoot(res, roots.item(i));
		}
		return res;
	}

	private void readRoot(LevelCollection res, Node node) {
		for (int i = 0; i < node.getChildNodes().getLength(); i++) {
			Node c = node.getChildNodes().item(i);
			if ("Title".equals(c.getNodeName()))
				res.setTitle(getText(c));
			else if ("LevelCollection".equals(c.getNodeName()))
				readLevelCollection(res, c);
		}
	}

	private void readLevelCollection(LevelCollection res, Node node) {
		res.setCopyright(getAttribute(node, "Copyright"));
		for (int i = 0; i < node.getChildNodes().getLength(); i++) {
			res.getLevels().add(readLevel(node.getChildNodes().item(i)));
		}
	}

	private Level readLevel(Node node) {
		Level res = new Level(Integer.parseInt(getAttribute(node, "Width")),
				Integer.parseInt(getAttribute(node, "Height")));
		res.setTitle(getAttribute(node, "Id"));
		for (int i = 0; i < node.getChildNodes().getLength(); i++) {
			String line = getText(node.getChildNodes().item(i));
			for (int n = 0; n < line.length(); n++) {
				res.setCell(n, i, CellKind.fromChar(line.charAt(n)));
			}
		}
		return res;
	}

	private static String getAttribute(Node node, String name) {
		return ((Attr) node.getAttributes().getNamedItem(name)).getValue();
	}

	private static String getText(Node node) {
		return ((Text) node.getFirstChild()).getData();
	}
}
